#pragma once

#include <Logger.h>
#include <Epoller.h>
#include <Channel.h>
#include <queue>
#include <thread>
#include <mutex>
#include <atomic>
#include <functional>
#include <sys/eventfd.h>
#include <CurrentThread.h>
#ifdef __linux__
#include <unistd.h>
#endif

class EventLoop
{
    using ChannelList = std::vector<Channel *>;

public:
    EventLoop();

    ~EventLoop();

    void loop();

    void quit();

    void updateChannel(Channel *channel);

    void removeChannel(Channel *channel);

    bool hasChannel(Channel *channel);

    /// @brief 判断是否当前线程是EventLoop所在的线程
    /// @return
    bool isInLoopThread() const;

    /// @brief 断言当前线程是否是EventLoop所在的线程,不是则打印错误信息
    void assertInLoopThread();

    void aborttNotInLoopThread();

    void doPendingFunctor();

    size_t queueSize();

    /// @brief 在当前loop中执行cb,用于在其他线程中向当前线程传递任务.如acceptor中向EventLoop传递新连接的任务
    /// @param cb
    void runInLoop(std::function<void()> cb);

    /// @brief 向队列中添加任务,用于在其他线程中向当前线程传递任务.
    void queueInLoop(std::function<void()> cb);

private:
    /// @brief 立即唤醒EventLoop所在的线程,执行任务队列的任务.
    void wakeup();

    /// @brief wakeup唤醒时进行read，并不是用来处理读事件的，所有的事件都通过channel的handleEvent处理
    void handleRead();

private:
    std::unique_ptr<Epoller> epoller_;
    std::unique_ptr<Channel> wakeupChannel_;
    Channel *currentActiveChannel_;
    std::mutex mutex_;
    std::vector<std::function<void()>> functors_;
    ChannelList activeChannels_;
    std::atomic<bool> quit_;
    int wakeupFd_;
    bool looping_;
    bool eventHandling_;
    bool callingPendingFunctors_;
    std::thread::id threadId_;
};